/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.helper;


import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.uml2.uml.Element;

import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagraminterchange2.di2.Di2Factory;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;

/**
 * Abstract class for modeler factories.
 * 
 * @author Remi SCHNEKENBURGER
 */
public abstract class DefaultModelerHelper implements IModelerHelper {

	/**
	 * Map that maps metaclasses to their factory.
	 */
	protected Map<Class, Object> creationFactoryMap = new HashMap<Class, Object>();

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.IModelerFactory#canExecute(java.lang.Class, com.cea.papyrus.diagraminterchange2.di2.GraphNode)
	 */
	/**
	 * 
	 * 
	 * @param objectToCreate 
	 * @param parent 
	 * 
	 * @return 
	 */
	public boolean canCreateGraphElement(Class objectToCreate, GraphElement parent) {
		Object object = getElementFactory(objectToCreate);

		if ((object != null) && (object instanceof IGraphElementHelper)) {
			return ((IGraphElementHelper) object).canCreateGraphElement(parent);
		}
		return false;
	}
	
	
	/**
	 * 
	 * 
	 * @param child 
	 * @param objectToCreate 
	 * @param parent 
	 * 
	 * @return 
	 */
	public boolean removeGraphElement(Class objectToCreate,GraphElement child, GraphElement parent) {
		Object object = getElementFactory(objectToCreate);

		if ((object != null) && (object instanceof IGraphElementHelper)) {
			return ((IGraphElementHelper) object).removeGraphElement(child, parent);
		}
		return false;
	}

	/**
	 * 
	 * 
	 * @param child 
	 * @param objectToCreate 
	 * @param parent 
	 * 
	 * @return 
	 */
	public GraphElement addGraphElement(Class objectToCreate,GraphElement child, GraphElement parent) {
		Object object = getElementFactory(objectToCreate);

		if ((object != null) && (object instanceof IGraphElementHelper)) {
			return ((IGraphElementHelper) object).addGraphElement(child, parent);		}
		return null;
	}
	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.IModelerFactory#canExecute(java.lang.Class, com.cea.papyrus.diagraminterchange2.di2.GraphElement, com.cea.papyrus.diagraminterchange2.di2.GraphElement)
	 */
	/**
	 * 
	 * 
	 * @param objectToCreate 
	 * @param target 
	 * @param source 
	 * 
	 * @return 
	 */
	public boolean canConnect(Class objectToCreate, Element source, Element target) {
		Object object = getElementFactory(objectToCreate);

		if ((object != null) && (object instanceof IGraphEdgeHelper)) {
			return ((IGraphEdgeHelper) object).canConnect(source,target);
		}

		return false;
	}

	/**
	 * 
	 * 
	 * @param type 
	 * @param target 
	 * @param link 
	 * @param source 
	 * 
	 * @return 
	 */
	public boolean connect(Class  type, Element source, Element target, Element link) {
		Object object = getElementFactory(type);

		if ((object != null) && (object instanceof IGraphEdgeHelper)) {
			return ((IGraphEdgeHelper) object).connect(source,target,link);
		}

		return false;
	}
	
	/**
	 * 
	 * 
	 * @param type 
	 * @param target 
	 * @param link 
	 * @param source 
	 * 
	 * @return 
	 */
	public boolean deconnect(Class  type, Element source, Element target, Element link) {
		Object object = getElementFactory(type);

		if ((object != null) && (object instanceof IGraphEdgeHelper)) {
			return ((IGraphEdgeHelper) object).deconnect(source,target,link);
		}

		return false;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.IModelerFactory#createElement(java.lang.Class, java.lang.String, org.eclipse.uml2.uml.Element)
	 */
	/**
	 * 
	 * 
	 * @param objectToCreate 
	 * @param name 
	 * @param parent 
	 * 
	 * @return 
	 */
	public Element createUMLElement(Class objectToCreate, String name, Element parent) {
		Object object = getElementFactory(objectToCreate);

		if ((object != null)) {
			return ((IGraphElementHelper) object).createUMLElement(name, parent);
		}

		return null;
	}
	
	/**
	 * 
	 * 
	 * @param element 
	 * @param objectToCreate 
	 * @param umlParent 
	 * 
	 * @return 
	 */
	public boolean addUMLElement(Class objectToCreate, Element element, Element umlParent) {
		Object object = getElementFactory(objectToCreate);

		if ((object != null)) {
			return ((IGraphElementHelper) object).addUMLElement(element, umlParent);
		}

		return false;
	}
	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.IModelerFactory#createElement(java.lang.Class, org.eclipse.uml2.uml.Element)
	 */
	/**
	 * 
	 * 
	 * @param objectToCreate 
	 * @param parent 
	 * 
	 * @return 
	 */
	public Element createUMLElement(Class objectToCreate, Element parent) {
		Object object = getElementFactory(objectToCreate);

		if ((object != null)) {
			return ((IGraphElementHelper) object).createUMLElement(parent);
		}

		return null;	
	}


	/**
	 * 
	 * 
	 * @param umlparent 
	 * @param objectToCreate 
	 * @param umlelement 
	 * 
	 * @return 
	 */
	public boolean removeElement(Class objectToCreate,Element umlelement, org.eclipse.uml2.uml.Element umlparent){
		Object object = getElementFactory(objectToCreate);

		if ((object != null) ) {
			return ((IGraphElementHelper) object).removeUMLElement(umlelement, umlparent);
		}

		return false;	
	}


	

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.IModelerFactory#createGraphNode(java.lang.Class, org.eclipse.uml2.uml.Package)
	 */
	/**
	 * 
	 * 
	 * @param umlChild 
	 * @param size 
	 * @param location 
	 * @param parent 
	 * 
	 * @return 
	 */
	public GraphElement createGraphElement(Element umlChild, GraphElement parent, Point location, Dimension size) {
		
		if ((umlChild != null)) {
			Object object = getElementFactory(umlChild.getClass().getInterfaces()[0]);
			return ((IGraphElementHelper) object).createGraphElement(umlChild, parent, location, size);
		} else {
			// no uml Child associated. Creates a simple graph Edge
			GraphEdge graphEdge=Di2Factory.eINSTANCE.createGraphEdge();
			graphEdge.setLineStyle("solid");
			graphEdge.setLineThickness(1);
			graphEdge.setForegroundColor(ColorConstants.black.getRGB());//black
			graphEdge.setBackgroundColor(ColorConstants.black.getRGB());//black
			graphEdge.setFontColor(ColorConstants.black.getRGB());//black
			graphEdge.setBorderColor(ColorConstants.black.getRGB());//black
			graphEdge.setIsVisible(true);//createUMLbridgee

			if(parent!=null){
				parent.getContained().add(graphEdge);
			}
			
			return graphEdge;
		}

		// return null;	
	}


	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.IModelerFactory#getId()
	 */
	/**
	 * 
	 * 
	 * @return 
	 */
	public abstract String getId();

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.IModelerFactory#isFactoryFor(java.lang.Class)
	 */
	/**
	 * 
	 * 
	 * @param elementClass 
	 * 
	 * @return 
	 */
	public boolean isFactoryFor(Class elementClass) {
		return creationFactoryMap.containsKey(elementClass);
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.IModelerFactory#getFactoryFor(java.lang.Class)
	 */
	/**
	 * 
	 * 
	 * @param elementClass 
	 * 
	 * @return 
	 */
	public Object getElementFactory(Class elementClass) {
		Object factory = creationFactoryMap.get(elementClass);
		
		// if elementClass is null obviously the searched factory will not be 
		// found.
		// In such a case no error is logged, this is usually due
		// to the fact that manipulated element is purely graphical and 
		// it has no corresponding UML element.
		if ((elementClass != null) && (factory == null)) {
			Debug.log(new Exception("No factory for : "+elementClass));
			return null;
		}
		return factory;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.factories.IModelerFactory#getDefinedMetaClasses()
	 */
	/**
	 * 
	 * 
	 * @return 
	 */
	public Set<Class> getDefinedMetaClasses() {
		return creationFactoryMap.keySet();
	}

}
